﻿using System.Reflection;
using System.Text.Json.Serialization;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Common.Authentication;
using Common.Autofac;
using Common.Filter;
using Common.Json;
using Common.Knife4Swagger;
using Common.Serilog;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Microsoft.Extensions.Hosting;
using Serilog;
using Steeltoe.Extensions.Configuration.Placeholder;

namespace Common;

public static class CommonWebAppBuilderExtensions
{
    public static void AddAppJwtAuthentication(this WebApplicationBuilder builder, string secret)
    {
        builder.Services.AddAuthorization();
        builder.Services.AddAuthentication(o =>
        {
            o.DefaultScheme = AppJwtBearerDefaults.AuthenticationScheme;
            o.DefaultChallengeScheme = AppJwtBearerDefaults.AuthenticationScheme;
        }).AddAppJwtBearer(o => { o.Key = secret; });
    }

    private static void AddSerilog(this WebApplicationBuilder builder)
    {
        var logger = new LoggerConfiguration()
            .Enrich.With<AppSourceContextEnricher>()
            .ReadFrom.Configuration(builder.Configuration)
            .CreateLogger();
        builder.Host.UseSerilog(logger);
    }

    public static void AddConfiguration(this WebApplicationBuilder builder, params string[] yamlFiles)
    {
        
        // 使用yaml配置
        foreach (var yamlFile in yamlFiles)
        {
            builder.Configuration.AddAppConfig(yamlFile);
        }
       
    }

    public static void UseAutofac(this WebApplicationBuilder builder, List<Assembly> assemblies)
    {
        builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

// 配置ioc容器
        builder.Host.ConfigureContainer<ContainerBuilder>(b =>
        {
            // b.RegisterModule<AutofacModule>();
            AutofacModule autofacModule = new(builder.Services, builder.Configuration, assemblies);
            b.RegisterModule(autofacModule);
        });
    }

    public static void SetupApplication(this WebApplicationBuilder builder)
    {
        builder.AddSerilog();

        builder.AddPlaceholderResolver();


        builder.AddAppJwtAuthentication(builder.Configuration.GetValue<string>("project:jwtKey"));


        // Add services to the container.
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();


        // 添加内存缓存
        builder.Services.AddMemoryCache(b => { });

        // 添加Controller
        builder.Services
            .AddControllers(c =>
            {
                c.Filters.Add<ControllerExceptionFilter>();
                c.Filters.Add<ValidateModelAttribute>();
                c.Filters.Add<AppActionFilter>();
            })
            .AddJsonOptions(o =>
            {
                o.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter());
                o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
            });


        builder.Services.Configure<ApiBehaviorOptions>(o => { o.SuppressModelStateInvalidFilter = true; });
    }

    public static void AddKnifeSwagger(this WebApplicationBuilder builder, Knife4UIConfig config)
    {
        // knifeUI支持
// 参考： https://github.com/luoyunchong/IGeekFan.AspNetCore.Knife4jUI
        builder.Services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = config.Title, Version = "v1" });
            c.AddServer(new OpenApiServer()
            {
                Url = "",
                Description = config.ServerDescription
            });
            c.CustomOperationIds(apiDesc =>
            {
                var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
                return controllerAction?.ControllerName + "-" + controllerAction?.ActionName;
            });
            c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, config.ProjectName), true);

            c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        },
                        Scheme = "oauth2",
                        Name = "Bearer",
                        In = ParameterLocation.Header,
                    },
                    new List<string>()
                }
            });

            //放置接口Auth授权按钮
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "Authorization Bearer Token",
                In = ParameterLocation.Header,
                Name = "Authorization",
                Type = SecuritySchemeType.ApiKey,
                BearerFormat = "Authorization: Bearer",
                Scheme = "oauth2",
                Reference = new OpenApiReference()
                {
                    Id = "Bearer",
                    Type = ReferenceType.SecurityScheme
                }
            });
        });
    }
}